//
// Created by gogoqiu on 2021/8/20.
//

#include <wx/stdpaths.h>
#include <wx/config.h>
#include "PreferenceStorage.h"
#include "../view/PreferencesFrame.h"
#include "../model/MyTagApp.h"
//
#define SQLITE_PATH "preference.db"
//App

/*
 * select
 * insert
 */

/*
 * list view
 * session
 */
/*
void PreferenceStorage::BuildView(){
    vector<PreferenceView*>::iterator _iterator;
    for(_iterator = preferences.begin();_iterator!=preferences.end(); _iterator++ ){
    //preferences.swap()
    }
}*/

static wxString GetWorkDirectory( )
{
    wxString strAppPath ;
    wxStandardPathsBase& wxStandardPaths = wxStandardPaths::Get();
    wxFileName exeFile(wxStandardPaths.GetExecutablePath());
    strAppPath = exeFile.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);

    return strAppPath ;
}

//
//path:
//
SqlitePreferenceStorage::SqlitePreferenceStorage( MyTagApp * _myTagApp ){
    //sqlite3_initialize();
    //sqlite3_shutdown();
    m_pDb = nullptr;
    this->myTagApp = _myTagApp;
    this->tag = myTagApp->getAppTag();
    //不存在会建立，所以相对不存在问题
    int ret = sqlite3_open( SQLITE_PATH, &m_pDb );
    //当前目录
    wxString curPath = GetWorkDirectory( );
    wxString temp;
    wxString db_path( SQLITE_PATH );
    temp.sprintf( L"Preference路径: %s%s", curPath, db_path );
    printf( "%s\n", temp.c_str().AsChar() );
    if( ret != SQLITE_OK ){
        //or call the signal to break all execute
        throw "打开Preferences数据库失败!";
        exit(-1);
    }
}

/**
 * 封装事件，UI
 *
 */
SqlitePreferenceStorage::~SqlitePreferenceStorage(){
    if( m_pDb ) {
        sqlite3_close(m_pDb);
    }
}

/*
 * main table:
 * app
 * id, key, value
 * default table:
 * key, default value
 * view table:
 * key, type
 *
 * keys
 * list
 *  "key TINYTEXT,"
 *  "type INTEGER,"
 *  CREATE TABLE `preferences` (
	`id`	INTEGER PRIMARY KEY AUTOINCREMENT,
	`tag`	TINYTEXT,
	`key`	TINYTEXT,
	`defaultValue`	TINYTEXT,
	`value`	TINYTEXT
);
 */
int SqlitePreferenceStorage::InitTable(){
    char *errmsg;
    /* 创建表 */
    const char *sql = "CREATE TABLE preferences("
                      "id INTEGER PRIMARY KEY AUTOINCREMENT,"
                      "tag TINYTEXT,"
                      "key TINYTEXT,"
                      "defaultValue TINYTEXT,"
                      "value TINYTEXT );" ;

    int ret = sqlite3_exec( m_pDb,sql,nullptr, nullptr, &errmsg );
    if( ret!=SQLITE_OK ) {
#ifdef _DEBUG_
        printf("%s\n", errmsg);
        sqlite3_free(errmsg);
        return -1;
#endif
    }
    return 0;
}

//如何关联日志
int SqlitePreferenceStorage::RunSql( wxString sql ){
    char *errmsg;
    const char *_sql;
    _sql = sql.mb_str(wxConvUTF8);
    int ret = sqlite3_exec(m_pDb, _sql,nullptr, nullptr, &errmsg);
    if( ret!=SQLITE_OK ) {
#ifdef _DEBUG_
        printf("%s\n%s\n", _sql, errmsg);
#endif
        sqlite3_free(errmsg);
        return -1;
    }
    return 0;
}

/*
 * */
int SqlitePreferenceStorage::Save(){
    wxString sql;
    sql.sprintf( "delete from preferences where tag='%s';", tag );
    //
    if( RunSql( sql )==-1 ){
        return -1;
    }
    vector<PreferenceItem*>::iterator _iterator;
    for(_iterator = preferences.begin();_iterator!=preferences.end(); _iterator++ ) {
        //preferences.swap()
        sql = _iterator.operator*()->getSql( tag );
        if( RunSql(sql)==-1 ){
            return -1;
        };
    }
    return 0;
}

/*
 *
 */
int SqlitePreferenceStorage::Save( vector<PreferenceItem*> items ){
    wxString sql;
    vector<PreferenceItem*>::iterator _iterator;
    for(_iterator = items.begin();_iterator!=items.end(); _iterator++ ) {
        //preferences.swap()
        sql = _iterator.operator*()->getSql( tag );
        if( RunSql(sql)==-1 ){
            return -1;
        };
    }
    return 0;
}

/*
 * 数据库不存在
 * 表不存在
 * 支持样式？
 * AppPreference{
 *  Keys = [];
 * }
 * ..
 * union
 * id key value
 */
int SqlitePreferenceStorage::Load(){

    wxString sql;

    const char * _sql;
    //const char*
    //char errmsg[256] = {0};
    char *errmsg;
    int result;
    /*
    int result = sqlite3_exec( m_pDb, _sql, NULL, NULL, &errmsg );
    if(result != SQLITE_OK )
    {
        //printf( “创建表失败，错误码:%d，错误原因:%s/n”, result, errmsg );
        return -1;
    }*/
    int nRow, nColumn;
    int i , j;
    int index;
    char **dbResult; //是 char ** 类型，两个*号
    //check first run, null database, null table
    sql.sprintf("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='%s';", "preferences" );
    _sql  = sql.mb_str(wxConvUTF8);
    result = sqlite3_get_table( m_pDb, _sql, &dbResult, &nRow, &nColumn, &errmsg );
    if( SQLITE_OK != result )
    {
        throw "Can't query the preferences from sqlite_master!";
        return -1;
    }
    char* s = dbResult[1];
    wxString count = s;
    if( count.IsSameAs("0")){
        InitTable();
        //
        this->myTagApp->getPreferenceCore()->OnWithoutPreferenceTable( this );
    }
    //
    this->myTagApp->getPreferenceCore()->OnPreferencePreLoad(this);
    //query data
    sql.clear();
    //
    sql.sprintf("select * from preferences where tag='%s';", tag );
    _sql  = sql.mb_str(wxConvUTF8);
    result = sqlite3_get_table( m_pDb, _sql, &dbResult, &nRow, &nColumn, &errmsg );
    wxString key, value, defaultValue;
    bool _valueIsNull;
    //
    if( SQLITE_OK == result )
    {
        //查询成功
        index = nColumn; //前面说过 dbResult 前面第一行数据是字段名称，从 nColumn 索引开始才是真正的数据
        //printf( "查到%d条记录/n", nRow );

        for(  i = 0; i < nRow ; i++ )
        {
            _valueIsNull = false;
            //printf( "第 %d 条记录/n", i+1 );
            for( j = 0 ; j < nColumn; j++ )
            {
                switch (j) {
                    case 0:
                        //id
                        break;
                    case 1:
                        //
                        break;
                    case 2:
                        key = dbResult [index];
                        break;
                    case 3:
                        if( dbResult [index] == 0 ){
                            _valueIsNull = true;
                        }
                        defaultValue = dbResult [index];
                        break;
                    case 4:
                        value = dbResult [index];
                        break;
                }
                /*
                 * int argc, char* argv[];
                 * row1: dbResult[0]: id, dbResult[1]:tag, dbResult[2]: key, dbResult[3]: defaultValue, dbResult[4]: value;
                 * row2: dbResult[5]: id
                 * ...
                 */
                //printf( "字段名:%s, 字段值:%s\n",  dbResult[j], dbResult [index] );
                ++index; // dbResult 的字段值是连续的，从第0索引到第 nColumn - 1索引都是字段名称，从第 nColumn 索引开始，后面都是字段值，它把一个二维的表（传统的行列表示法）用一个扁平的形式来表示
            }
            //printf( "-------/n" );
            this->preferences.push_back( new PreferenceItem( key, value, defaultValue, _valueIsNull ) );
        }
    }else{
        //printf("%s\n", errmsg);
        //sqlite3_free(errmsg);
        return -1;
    }
    //到这里，不论数据库查询是否成功，都释放 char** 查询结果，使用 sqlite 提供的功能来释放
    sqlite3_free_table( dbResult );
    //关闭数据库
    //sqlite3_close( m_pDb );
    return 0;
}

MysqlPreferenceStorage::MysqlPreferenceStorage() = default;

MysqlPreferenceStorage::~MysqlPreferenceStorage() = default;

int MysqlPreferenceStorage::Save() {
    return 0;
}
#ifdef __Win32__

//reg key root
RegisterPreferenceStorage::RegisterPreferenceStorage(){

}
#endif

/*
 *
 */
int SqlitePreferenceStorage::updateItem(const wxString& key, const wxString& value) {
    char *errmsg;

    wxString sql;
    sql.sprintf( "update preferences set `value`= '%s' where key='%s';", value, key );
    const char * _sql ;//= sql.mb_str(wxConvUTF8);
    _sql = sql.mb_str(wxConvUTF8);
    int result = sqlite3_exec(m_pDb, _sql,nullptr,nullptr,&errmsg);
    if( SQLITE_OK == result )
        return 0;
    else {
#ifdef _DEBUG_
        printf("%s\n%s\n", _sql, errmsg);
#endif
        return -1;
    }
}

//SqlitePreferenceStorage* SqlitePreferenceStorage::instance = nullptr;
/**

 */
 /*
SqlitePreferenceStorage *SqlitePreferenceStorage::getDefaultSharedPreferences( const wxString & TAG ) {
    //APP_TAG
    if( instance== nullptr ){
        instance = new SqlitePreferenceStorage( TAG );
    }
    return instance;
}*/

